package com.mango.Tools;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 元注解是什么意思呢？
 * 
 * 元注解是可以注解到注解上的注解，或者说元注解是一种基本注解，但是它能够应用到其它的注解上面。
 * 如果难于理解的话，你可以这样理解。元注解也是一张标签，但是它是一张特殊的标签，它的作用和目的就是给其他普通的标签进行解释说明的。
 * 元标签有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。
 * 
 * @author Mango
 *
 */
public class MyAnnotations {
	/**
	 * 使用关键字 @interface 定义一个 注解TestAnnotation
	 * 
	 * @Target 有下面的取值
	 * 
	 *         ElementType.ANNOTATION_TYPE 可以给一个注解进行注解 ElementType.CONSTRUCTOR
	 *         可以给构造方法进行注解 ElementType.FIELD 可以给属性进行注解 ElementType.LOCAL_VARIABLE
	 *         可以给局部变量进行注解 ElementType.METHOD 可以给方法进行注解 ElementType.PACKAGE
	 *         可以给一个包进行注解 ElementType.PARAMETER 可以给一个方法内的参数进行注解 ElementType.TYPE
	 *         可以给一个类型进行注解，比如类、接口、枚举
	 * @author Mango
	 *
	 */
	@Inherited // Inherited 是继承的意思，但是它并不是说注解本身可以继承，而是说如果一个超类被 @Inherited
				// 注解过的注解进行注解的话，那么如果它的子类没有被任何注解应用的话，那么这个子类就继承了超类的注解。 
	@Retention(RetentionPolicy.RUNTIME) // 指明了标签张贴的时间周期
	@Target(ElementType.TYPE) // @Target 注解时，这个注解就被限定了运用的场景
	public @interface TestAnnotation {
		/*
		 * // 注解的属性也叫做成员变量。注解只有成员变量，没有方法。 // 注解的成员变量在注解的定义中以“无形参的方法”形式来声明，
		 * //其方法名定义了该成员变量的名字，其返回值定义了该成员变量的类型。 //注解中定义属性时它的类型必须是 8 种基本数据类型外加
		 * 类、接口、注解及它们的数组
		 */
		int id() default 0;

		String msg() default "";
	}

	/**
	 * 创建一个类 Test,然后在类定义的地方加上 @TestAnnotation 就可以用 TestAnnotation 注解这个类 可以简单理解为将
	 * TestAnnotation 这张标签贴到 Test 这个类上面。
	 * 
	 * @author Mango
	 *
	 */
	@TestAnnotation(id = 3, msg = "hello annotation")
	class TestClass {

	}

	/**
	 * Persons 是一张总的标签，上面贴满了 Person 这种同类型但内容不一样的标签。把 Persons 给一个 SuperMan
	 * 贴上，相当于同时给他贴了程序员、产品经理、画家的标签。
	 * 
	 * @author Mango
	 *
	 */
	@Inherited
	@Retention(RetentionPolicy.RUNTIME)
	@Target(ElementType.TYPE)
	public @interface Persons {
		Person[] value();
	}

	@Repeatable(Persons.class)
	public @interface Person {
		String role() default "";
	}

	@Person(role = "artist")
	@Person(role = "coder")
	@Person(role = "PM")
	public class SuperMan {

	}

}
